// UNIXSocketClient.h
//
// Copyright (c) 2008 Bojan Rajkovic
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "Utility.h"

#define LINE_BUFFER_SIZE 4096

using namespace LinPulseApplet;

namespace LinPulseApplet {

	typedef unsigned char byte;
		
	class SocketException : public std::exception {
	
		private:
			int error;
			const char* message;
			
		public:
		
			SocketException(int Error) {
				this->error = Error;
				this->message = NULL;
				Utility::LogMessage(Utility::FormatString("SocketException: %s", what()), M_ERROR);
			}
			
			SocketException(const char* Message) {
				this->error = 0;
				this->message = Message;
			}
		
			virtual const char* what() const throw() {
				if (message == NULL) { 
					std::string whatMessage = Utility::FormatString(_("Got error %d: %s"), error, strerror(error));
					return whatMessage.c_str();
				}
				else return message;
			}
	};

	class UNIXClientSocket {
	
		private:
			
			int clientSocket;
			FILE* clientSocketDescriptor;
			std::string socketLocation;
			
		public:
			
			// Constructors
			UNIXClientSocket(std::string);
			// Destructor
			~UNIXClientSocket();
			// Read until we've read int bytes.
			std::string Read(int);
			// Read a line from the socket--ie. until we reach \n,
			// We'll have to do some guessing at the length of the response,
			// but a buffer size of 4 KiB should be sufficient.
			std::string ReadLine();
			// Read n bytes and return them as a byte[].
			byte* ReadBytes(int);
			// Write the string to the socket, return how many bytes we wrote
			int Write(std::string);
			// Get the hostname we're connected to
			std::string SocketLocation() { return this->socketLocation; }
			// Get the socket descriptor (the return value from socket())
			int SocketDescriptor() { return this->clientSocket; }
			// Get the FILE* to the socket
			FILE* SocketFileDescriptor() { return this->clientSocketDescriptor; }
			void CloseRemoteSocket() { 
				close(clientSocket);
				fclose(clientSocketDescriptor);
			}
	};

}